﻿#region

using System.ComponentModel;
using System.Linq;
using System.Threading;

#endregion

namespace Radovici.SharedLibrary
{
    public abstract class Notifiable : INotifyPropertyChanged
    {
        //[NonSerialized] //NOTE: Silverlight 2 excludes serializable attributes.

        #region Private fields

        private readonly SynchronizationContext _context;
        private readonly object _lock = new object();

        #endregion

        private PropertyChangedEventHandler _propertyChanged;

        public Notifiable()
        {
            _context = SynchronizationContext.Current;
        }

        public SynchronizationContext Context
        {
            get { return _context ?? SynchronizationContext.Current; }
        }        

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged
        {
            add
            {
                lock (_lock)
                {
                    _propertyChanged += value;
                }
            }
            remove
            {
                lock (_lock)
                {
                    _propertyChanged -= value;
                }
            }
        }

        #endregion

        public void Notify(string propertyName)
        {
            Context.Send(NotifyContext, propertyName);
        }

        private void NotifyContext(object state)
        {
            lock (_lock)
            {
                var propertyName = state as string;
                if (!string.IsNullOrEmpty(propertyName))
                {
                    if (_propertyChanged != null)
                    {
                        foreach (PropertyChangedEventHandler del in _propertyChanged.GetInvocationList())
                        {
                            if (_propertyChanged.GetInvocationList().Contains(del))
                            {
                                del(this, new PropertyChangedEventArgs(propertyName)); //NOTE: Delegating w/in a lock is bad news...
                            }
                            else
                            {
                                Debug.WriteLine(string.Format("WARNING: Binding to property {0} failed for delegate {1}; HACK: http://silverlight.net/forums/t/58548.aspx",
                                        propertyName, string.Format("{0}:{1}", del.Target, del.Method.Name)));
                            }
                        }
                    }
                }
            }
        }
    }
}